updateVariantProduct
- ๐ฌ๐ง English
- ๐ฎ๐น Italian
Function Name: updateVariantProduct
Author: Domenico Cerone Creation Date: 09/10/2025
Last Reviewer: Domenico Cerone
Trigger: HTTPS (onRequest)
Purpose: Complete workflow for updating existing product and variant data from catalog orders. Always downloads updated JSON and images, then updates existing documents in both Products and Variants collections. This function refreshes existing data with the latest versions from Safilo APIs without creating new documents.
Detailed Functionalityโ
This Firebase Function performs a comprehensive update workflow for existing products and variants with dynamic batch processing optimized for refreshing data from catalog orders.
1. CATALOG ORDER LOADINGโ
- Receives
catalogOrderIdas input parameter - Loads document from 'CatalogOrders' collection
- Extracts
list_3d_assets_resultswith product array - Each element contains: skuCode, productRef, variantRef (existing document IDs)
- Processes all products in list_3d_assets_results that have valid references
2. DYNAMIC BATCH PROCESSINGโ
Batch configuration:
- Fixed batch size: 10 elements with 500ms pauses between batches
- Sequential batch processing to avoid Safilo API overload
- Parallel processing within each batch for optimal performance
- Individual product error handling without blocking others
- Detailed progress logging for all operations
3. API CALLS WITH AUTOMATIC RETRY (ALWAYS EXECUTED)โ
API Details:
- getModels API: https://commportal-api.safilo.com/.../spaarkly.getModels
- getImages API: https://safilo-pd-cdn002.safilo.com/damapi/damimage/public/sfcc.getimagenofb
- Purpose: Download updated product data and images (ALWAYS, even if existing)
- Retry System: 3 attempts with progressive delay (100ms โ 300ms โ 600ms)
For each product:
- ALWAYS calls getModels API to get updated JSON data (~50KB)
- ALWAYS downloads 8 product images (detail 00-07) with imagesize=big
- Images are re-downloaded even if they exist (they might have changed)
- Automatic retry system with progressive delays
- Saves updated JSON to Firebase Storage with UUID tokens
- Creates updated mapped JSON with public URLs
4. DOCUMENT MAPPING AND PROCESSINGโ
Dynamic mapping system:
- Dynamic parsing of mapping_template.xlsx from Firebase Storage
- SAP metadata loading from Firebase Storage (metadata_files/)
- Data extraction from updated JSON based on template rules
- Automatic SAP codes translation
- Special field handling: โ SPECIAL_PRODUCT_DESCRIPTIONS: Creates separate language fields (description_en, description_it, etc.) โ SPECIAL_IMAGE_NAMES: Extracts public URLs with tokens โ specific posters (00,07,02,01) + list_images array
- Updated mapped JSON save on Storage with public URL
Related Components:
- updateProductHelper - Handles Products collection updates with thread-safe tag regeneration
- updateVariantHelper - Handles Variants collection updates with complete field refresh
- tagUtils - Thread-safe tag creation utilities with mutex synchronization to prevent duplicates
5. EXISTING DOCUMENT UPDATESโ
Update Logic:
- Updates existing Products document using productRef (NO creation of new documents)
- Updates existing Variants document using variantRef (NO creation of new documents)
- Regenerates ALL tags using thread-safe tagUtils.js functions
- Updates ALL fields derived from mapped JSON (descriptions, images, tags, dates, etc.)
- Maintains workflow fields unchanged (variants_map, list_variants, assignedTo, status, etc.)
Differences with populateVariantFromSkuโ
Update vs Creation:
- updateVariantProduct: ONLY updates existing documents
- populateVariantFromSku: creation/update with complex logic
Different Input:
- updateVariantProduct: uses productRef/variantRef from CatalogOrder
- populateVariantFromSku: searches/creates documents by modelName/skuModel
Different Purpose:
- updateVariantProduct: refresh existing data with updated versions
- populateVariantFromSku: initial population from scratch
Identical Tag Handling:
- Same tag creation/search logic using tagUtils
- Thread-safe to avoid duplicates
- Automatic translations (Gender โ Italian)
- Normalized brands for Line tags
Products Collection Fields Updatedโ
The function updates the following fields in the Products collection with data extracted from the updated mapped JSON:
Base Fields:
ageโ catAgeForGendermanufacturedProductStatusโ manufacturedProductStatusrxAbleโ rxAble (converted from "YES"/"NO" to boolean)mainBrandRefโ ID brand (searches/creates in MainBrands collection)upcCodeโ upcCode
Image Fields:
imgUrlโ poster (from current variant)thumbnailโ poster (from current variant)urlImageโ poster (from current variant)
Timestamp Fields:
lastUpdateโ current timestamp (always updated, Date object)productReleaseDateโ productReleaseDate (if present in mapped JSON, Date object)productEndDateโ productEndDate (if present in mapped JSON, Date object)
Multilingual Descriptions:
descriptionEnโ description_endescriptionItโ description_itdescriptionEsโ description_esdescriptionFrโ description_frdescriptionDeโ description_de
Tags Arrays (completely regenerated):
list_frame_color_tagsโ [frameColor tag IDs from Tags collection]list_size_tagsโ [size tag IDs from Tags collection]list_line_tagsโ [line tag IDs linked to normalized brand]list_tagsโ [catType, catAgeForGender, catGender, catForma, catMaterialOne, polarised, catLensesTreat, hingeType]
Fields Maintained Unchanged:
modelName(primary identifier)variants_map(existing variant management)list_variants(existing variant IDs)availableVariants(existing count)
Variants Collection Fields Updatedโ
The function updates the following fields in the Variants collection with data extracted from the updated mapped JSON:
Base Fields:
eanCodeโ eanCodeframeColorโ frameColorlensesColorโ lensesColorglassesNameโ glassesNamemainBrandRefโ ID brand (searches/creates in MainBrands collection)upcCodeโ upcCode
Image Fields:
posterโ poster (view 00 - main frontal)poster2โ poster2 (view 07 - side angle)poster3โ poster3 (view 02 - frontal detail)poster4โ poster4 (view 01 - alternative angle)
Boolean Fields:
isADVโ isADV (converted from "YES"/"NO" to boolean)
Size Object (all fields as strings):
size.bridgeโ bridgesize.frameWidthโ frameWidthsize.lensHeightโ lensHeightsize.lensWidthโ lensWidthsize.sizeโ sizesize.templeLengthโ templeLengthsize.frontHeightโ frontHeightsize.hingeToHingeโ hingeToHingesize.lensCircumferenceโ lensCircumferencesize.lensAngleโ lensAnglesize.phantoscopicAngleโ phantoscopicAngle
Timestamp Fields (as JavaScript Date objects):
lastUpdateโ current timestamp (always updated, Date object)skuReleaseDateโ skuReleaseDate (if present in mapped JSON, Date object)skuEndDateโ skuEndDate (if present in mapped JSON, Date object)advStartDateโ advStartDate (if present in mapped JSON, Date object)advEndDateโ advEndDate (if present in mapped JSON, Date object)
Tags Arrays (completely regenerated):
list_size_color_tagsโ [frameColor tag ID, size tag ID] (searches/creates in Tags collection)list_imagesโ list_images (array of objects with view and url of images)
Fields Maintained Unchanged:
skuModel(primary identifier)assignedTo,assignmentDate,dataTakenbatch,productRef,catalogOrdersRef,prioritiesModelingloadingId,mainModel,modelPriority,modelViewerUrlmodify_model(complete object)posterNoBackground,primaryFrameColorHex,primaryLensesColorHexpriority,refLogVariant,secondaryFrameColorHex,secondaryLensesColorHexstatus,templeColorurlDE,urlES,urlFR,urlGlobal,urlGlobalComplete, etc.variantCode,list_notes
CatalogOrder Document Structure Requiredโ
Important: The function input is only the catalogOrderId. The function then loads the CatalogOrder document from Firestore and expects it to contain the following structure:
Required Fields in CatalogOrder Document:
clientId: ID of the clientlist_3d_assets_results: array of products with skuCode, productRef, variantReforderName: name of the orderprofile: client email
Product Structure in list_3d_assets_results:
{
"skuCode": "20637008650QT",
"productRef": "existing_product_document_id",
"variantRef": "existing_variant_document_id"
}
Note: The productRef and variantRef must point to existing documents in the Products and Variants collections respectively. The function will update these existing documents with fresh data from Safilo APIs.
Input (Payload)โ
Method: POST
Headers:
Content-Type: application/json
Body:
{
"catalogOrderId": "evPBsLgU2qkGl0wCCUan"
}
Parameters:
catalogOrderId(string, required): Unique identifier of the catalog order to process
Output (Success)โ
{
"success": true,
"catalogOrderId": "evPBsLgU2qkGl0wCCUan",
"totalProducts": 3,
"successCount": 2,
"errorCount": 1,
"processedProducts": [
{
"success": true,
"skuCode": "20637008650QT",
"productRef": "existing_product_id",
"variantRef": "existing_variant_id",
"productOperation": "update",
"variantOperation": "update",
"message": "Prodotto 20637008650QT aggiornato con successo",
"apiCalls": {
"getModels (file .json)": "https://...spaarkly.getModels?sizeCode=...",
"getImages (thumbnail images)": "https://safilo-pd-cdn002.safilo.com/..."
},
"productUpdateDetails": {
"success": true,
"operation": "update",
"documentId": "existing_product_id",
"updatedFields": ["age", "imgUrl", "list_tags", ...]
},
"variantUpdateDetails": {
"success": true,
"operation": "update",
"documentId": "existing_variant_id",
"updatedFields": ["poster", "size", "list_size_color_tags", ...]
}
}
],
"message": "Aggiornamento completato per CatalogOrder evPBsLgU2qkGl0wCCUan: 2/3 prodotti aggiornati con successo",
"requestId": "UPD_1728123456789_abc123def"
}
Technical Specificationsโ
Firebase Function Configuration:
- Timeout: 1800 seconds (30 minutes)
- Memory: 1GiB - optimized for update operations
- Region: europe-central2 - optimal performance for Europe
- CORS: Enabled for frontend calls
Testingโ
URL (if HTTPS): http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct
Test with Emulator:
- Start Firebase emulator:
firebase emulators:start --only functions - Ensure you're using Node.js version 20:
nvm use 20 - Test with curl:
curl -X POST "http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct" \
-H "Content-Type: application/json" \
-d '{
"catalogOrderId": "evPBsLgU2qkGl0wCCUan"
}'
Postman Testing:
- Method: POST
- URL:
http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct - Headers:
- Key:
Content-Type - Value:
application/json
- Key:
- Body: raw JSON (see examples above)
Deploy Commandโ
firebase deploy --only functions:updateVariantProduct
Production URLโ
Live Function: https://europe-central2-arshades-7e18a.cloudfunctions.net/updateVariantProduct
Function Name: updateVariantProduct
Autore: Domenico Cerone Data di creazione: 09/10/2025
Last Reviewer: Domenico Cerone
Trigger: HTTPS (onRequest)
Purpose: Workflow completo per l'aggiornamento di dati prodotto e variante esistenti da ordini catalogo. Scarica sempre JSON e immagini aggiornati, poi aggiorna documenti esistenti in entrambe le collezioni Products e Variants. Questa funzione aggiorna i dati esistenti con le versioni piรน recenti dalle API Safilo senza creare nuovi documenti.
Funzionamento Dettagliatoโ
Questa Firebase Function esegue un workflow completo di aggiornamento per prodotti e varianti esistenti con batch processing dinamico ottimizzato per il refresh dei dati da ordini catalogo.
1. CARICAMENTO CATALOG ORDERโ
- Riceve
catalogOrderIdcome parametro di input - Carica documento dalla collezione 'CatalogOrders'
- Estrae
list_3d_assets_resultscon array di prodotti - Ogni elemento contiene: skuCode, productRef, variantRef (ID documenti esistenti)
- Processa tutti i prodotti in list_3d_assets_results che hanno riferimenti validi
2. PROCESSING BATCH DINAMICOโ
Configurazione batch:
- Dimensione batch fissa: 10 elementi con pause 500ms tra batch
- Processing batch sequenziale per evitare sovraccarico API Safilo
- Processing parallelo all'interno di ogni batch per prestazioni ottimali
- Gestione errori per singolo prodotto senza bloccare gli altri
- Logging dettagliato del progresso per tutte le operazioni
3. CHIAMATE API CON RETRY AUTOMATICO (SEMPRE ESEGUITE)โ
Dettagli API:
- API getModels: https://commportal-api.safilo.com/.../spaarkly.getModels
- API getImages: https://safilo-pd-cdn002.safilo.com/damapi/damimage/public/sfcc.getimagenofb
- Scopo: Scaricare dati prodotto e immagini aggiornati (SEMPRE, anche se esistenti)
- Sistema Retry: 3 tentativi con delay progressivo (100ms โ 300ms โ 600ms)
Per ogni prodotto:
- SEMPRE chiama getModels API per ottenere JSON aggiornato (~50KB)
- SEMPRE scarica 8 immagini prodotto (detail 00-07) con imagesize=big
- Le immagini vengono ri-scaricate anche se esistono (potrebbero essere cambiate)
- Sistema di retry automatico con delay progressivi
- Salva JSON aggiornato su Firebase Storage con token UUID
- Crea JSON mappato aggiornato con URL pubblici
4. MAPPING E PROCESSING DOCUMENTIโ
Sistema mapping dinamico:
- Parsing dinamico mapping_template.xlsx da Firebase Storage
- Caricamento metadata SAP da Firebase Storage (metadata_files/)
- Estrazione dati dal JSON aggiornato basata su template rules
- Applicazione traduzioni SAP codes automatiche
- Gestione campi speciali: โ SPECIAL_PRODUCT_DESCRIPTIONS: Crea campi separati per lingua (description_en, description_it, etc.) โ SPECIAL_IMAGE_NAMES: Estrae URL pubblici con token โ poster specifici (00,07,02,01) + array list_images
- Salvataggio JSON mappato aggiornato su Storage con URL pubblico
Componenti Correlati:
- updateProductHelper - Gestisce aggiornamenti collezione Products con rigenerazione tag thread-safe
- updateVariantHelper - Gestisce aggiornamenti collezione Variants con refresh completo campi
- tagUtils - Utilitร creazione tag thread-safe con sincronizzazione mutex per prevenire duplicati
5. AGGIORNAMENTI DOCUMENTI ESISTENTIโ
Logica Aggiornamento:
- Aggiorna documento Products esistente usando productRef (NESSUNA creazione di nuovi documenti)
- Aggiorna documento Variants esistente usando variantRef (NESSUNA creazione di nuovi documenti)
- Rigenera TUTTI i tag usando funzioni tagUtils.js thread-safe
- Aggiorna TUTTI i campi derivati dal JSON mappato (descrizioni, immagini, tag, date, etc.)
- Mantiene campi workflow invariati (variants_map, list_variants, assignedTo, status, etc.)
Differenze con populateVariantFromSkuโ
Aggiornamento vs Creazione:
- updateVariantProduct: SOLO aggiornamenti di documenti esistenti
- populateVariantFromSku: creazione/aggiornamento con logica complessa
Input Diverso:
- updateVariantProduct: usa productRef/variantRef da CatalogOrder
- populateVariantFromSku: cerca/crea documenti per modelName/skuModel
Scopo Diverso:
- updateVariantProduct: refresh dati esistenti con versioni aggiornate
- populateVariantFromSku: popolamento iniziale da zero
Gestione Tag Identica:
- Stessa logica di creazione/ricerca tag usando tagUtils
- Thread-safe per evitare duplicati
- Traduzioni automatiche (Gender โ italiano)
- Brand normalizzati per tag Line
Campi Aggiornati Collezione Productsโ
La funzione aggiorna i seguenti campi nella collezione Products con dati estratti dal JSON mappato aggiornato:
Campi Base:
ageโ catAgeForGendermanufacturedProductStatusโ manufacturedProductStatusrxAbleโ rxAble (convertito da "YES"/"NO" a boolean)mainBrandRefโ ID brand (cerca/crea nella collezione MainBrands)upcCodeโ upcCode
Campi Immagini:
imgUrlโ poster (dalla variante corrente)thumbnailโ poster (dalla variante corrente)urlImageโ poster (dalla variante corrente)
Campi Timestamp:
lastUpdateโ timestamp corrente (sempre aggiornato, oggetto Date)productReleaseDateโ productReleaseDate (se presente nel JSON mappato, oggetto Date)productEndDateโ productEndDate (se presente nel JSON mappato, oggetto Date)
Descrizioni Multilingua:
descriptionEnโ description_endescriptionItโ description_itdescriptionEsโ description_esdescriptionFrโ description_frdescriptionDeโ description_de
Array Tags (completamente rigenerati):
list_frame_color_tagsโ [ID tag frameColor dalla collezione Tags]list_size_tagsโ [ID tag size dalla collezione Tags]list_line_tagsโ [ID tag line collegati al brand normalizzato]list_tagsโ [catType, catAgeForGender, catGender, catForma, catMaterialOne, polarised, catLensesTreat, hingeType]
Campi Mantenuti Invariati:
modelName(identificatore principale)variants_map(gestione varianti esistente)list_variants(ID varianti esistenti)availableVariants(conteggio esistente)
Campi Aggiornati Collezione Variantsโ
La funzione aggiorna i seguenti campi nella collezione Variants con dati estratti dal JSON mappato aggiornato:
Campi Base:
eanCodeโ eanCodeframeColorโ frameColorlensesColorโ lensesColorglassesNameโ glassesNamemainBrandRefโ ID brand (cerca/crea nella collezione MainBrands)upcCodeโ upcCode
Campi Immagini:
posterโ poster (vista 00 - frontale principale)poster2โ poster2 (vista 07 - angolazione laterale)poster3โ poster3 (vista 02 - dettaglio frontale)poster4โ poster4 (vista 01 - angolazione alternativa)
Campi Boolean:
isADVโ isADV (convertito da "YES"/"NO" a boolean)
Oggetto Size (tutti i campi come stringhe):
size.bridgeโ bridgesize.frameWidthโ frameWidthsize.lensHeightโ lensHeightsize.lensWidthโ lensWidthsize.sizeโ sizesize.templeLengthโ templeLengthsize.frontHeightโ frontHeightsize.hingeToHingeโ hingeToHingesize.lensCircumferenceโ lensCircumferencesize.lensAngleโ lensAnglesize.phantoscopicAngleโ phantoscopicAngle
Campi Timestamp (come oggetti Date JavaScript):
lastUpdateโ timestamp corrente (sempre aggiornato, oggetto Date)skuReleaseDateโ skuReleaseDate (se presente nel JSON mappato, oggetto Date)skuEndDateโ skuEndDate (se presente nel JSON mappato, oggetto Date)advStartDateโ advStartDate (se presente nel JSON mappato, oggetto Date)advEndDateโ advEndDate (se presente nel JSON mappato, oggetto Date)
Array Tags (completamente rigenerati):
list_size_color_tagsโ [ID tag frameColor, ID tag size] (cerca/crea nella collezione Tags)list_imagesโ list_images (array di oggetti con view e url delle immagini)
Campi Mantenuti Invariati:
skuModel(identificatore principale)assignedTo,assignmentDate,dataTakenbatch,productRef,catalogOrdersRef,prioritiesModelingloadingId,mainModel,modelPriority,modelViewerUrlmodify_model(oggetto completo)posterNoBackground,primaryFrameColorHex,primaryLensesColorHexpriority,refLogVariant,secondaryFrameColorHex,secondaryLensesColorHexstatus,templeColorurlDE,urlES,urlFR,urlGlobal,urlGlobalComplete, etc.variantCode,list_notes
Struttura Documento CatalogOrder Richiestaโ
Importante: L'input della funzione รจ solo il catalogOrderId. La funzione poi carica il documento CatalogOrder da Firestore e si aspetta che contenga la seguente struttura:
Campi Richiesti nel Documento CatalogOrder:
clientId: ID del clientelist_3d_assets_results: array di prodotti con skuCode, productRef, variantReforderName: nome dell'ordineprofile: email del cliente
Struttura Prodotto in list_3d_assets_results:
{
"skuCode": "20637008650QT",
"productRef": "id_documento_product_esistente",
"variantRef": "id_documento_variant_esistente"
}
Nota: I campi productRef e variantRef devono puntare a documenti esistenti rispettivamente nelle collezioni Products e Variants. La funzione aggiornerร questi documenti esistenti con dati aggiornati dalle API Safilo.
Input (Payload)โ
Metodo: POST
Headers:
Content-Type: application/json
Body:
{
"catalogOrderId": "evPBsLgU2qkGl0wCCUan"
}
Parametri:
catalogOrderId(string, richiesto): Identificatore unico dell'ordine catalogo da processare
Output (Successo)โ
{
"success": true,
"catalogOrderId": "evPBsLgU2qkGl0wCCUan",
"totalProducts": 3,
"successCount": 2,
"errorCount": 1,
"processedProducts": [
{
"success": true,
"skuCode": "20637008650QT",
"productRef": "id_product_esistente",
"variantRef": "id_variant_esistente",
"productOperation": "update",
"variantOperation": "update",
"message": "Prodotto 20637008650QT aggiornato con successo",
"apiCalls": {
"getModels (file .json)": "https://...spaarkly.getModels?sizeCode=...",
"getImages (thumbnail images)": "https://safilo-pd-cdn002.safilo.com/..."
},
"productUpdateDetails": {
"success": true,
"operation": "update",
"documentId": "id_product_esistente",
"updatedFields": ["age", "imgUrl", "list_tags", ...]
},
"variantUpdateDetails": {
"success": true,
"operation": "update",
"documentId": "id_variant_esistente",
"updatedFields": ["poster", "size", "list_size_color_tags", ...]
}
}
],
"message": "Aggiornamento completato per CatalogOrder evPBsLgU2qkGl0wCCUan: 2/3 prodotti aggiornati con successo",
"requestId": "UPD_1728123456789_abc123def"
}
Specifiche Tecnicheโ
Configurazione Firebase Function:
- Timeout: 1800 secondi (30 minuti)
- Memoria: 1GiB - ottimizzata per operazioni di aggiornamento
- Regione: europe-central2 - performance ottimali per Europa
- CORS: Abilitato per chiamate da frontend
Testingโ
URL (if HTTPS): http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct
Test con Emulator:
- Avviare l'emulatore Firebase:
firebase emulators:start --only functions - Assicurarsi di usare Node.js versione 20:
nvm use 20 - Testare con curl:
curl -X POST "http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct" \
-H "Content-Type: application/json" \
-d '{
"catalogOrderId": "evPBsLgU2qkGl0wCCUan"
}'
Test con Postman:
- Metodo: POST
- URL:
http://127.0.0.1:5001/arshadesstaging/europe-central2/updateVariantProduct - Headers:
- Key:
Content-Type - Value:
application/json
- Key:
- Body: raw JSON (vedi esempi sopra)
Deploy Commandโ
firebase deploy --only functions:updateVariantProduct
URL di Produzioneโ
Funzione Live: https://europe-central2-arshades-7e18a.cloudfunctions.net/updateVariantProduct